home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 19 / CU Amiga Magazine's Super CD-ROM 19 (1998)(EMAP Images)(GB)[!][issue 1998-02].iso / CUCD / Programming / LEDA / source / src / graph_alg / _mwb_matching.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-16  |  7.0 KB  |  294 lines

  1. /*******************************************************************************
  2. +
  3. +  LEDA  3.1c
  4. +
  5. +
  6. +  _mwb_matching.c
  7. +
  8. +
  9. +  Copyright (c) 1994  by  Max-Planck-Institut fuer Informatik
  10. +  Im Stadtwald, 6600 Saarbruecken, FRG     
  11. +  All rights reserved.
  12. *******************************************************************************/
  13.  
  14.  
  15.  
  16. /*******************************************************************************
  17. *                                                                              *
  18. *  MAX_WEIGHT_BIPARTITE_MATCHING  (maximum weight bipartite matching)          *
  19. *                                           *
  20. *  modified 01/94, M.Paul                               *
  21. *                                                                              *
  22. *******************************************************************************/
  23.  
  24.  
  25. #include <LEDA/graph_alg.h>
  26. #include <LEDA/node_pq.h>
  27.  
  28. static list<edge> compute_MWBM( graph& G,
  29.                              const list<node>& A, const list<node>& B,
  30.                              const edge_array<num_type>& weight );
  31.  
  32.  
  33.  
  34. list<edge> MAX_WEIGHT_BIPARTITE_MATCHING( graph& G,
  35.                         const list<node>& A, const list<node>& B,
  36.                         const edge_array<num_type>& weight )
  37. {
  38.   if( A.size()==0 || B.size()==0 ) 
  39.     return 0;
  40.  
  41.   /* change the graph such that A becomes the node set with
  42.      smaller cardinality (if necessary)
  43.    */
  44.   if( B.size() < A.size() ) {
  45.     G.rev();
  46.     list<edge> mwm = compute_MWBM( G, B, A, weight );
  47.     G.rev();
  48.     return mwm;
  49.   }
  50.   else
  51.     return compute_MWBM( G, A, B, weight );
  52. }
  53.  
  54.  
  55.  
  56. /* return the list of possible endpoints of augmenting paths which
  57.    only need a minimal change of the dual function u
  58.  */
  59. static list<node> dijkstra( const graph& G, 
  60.                 const node_list& free,
  61.                             const node_array<num_type>& u,
  62.                             const edge_array<num_type>& weight,
  63.                                   num_type maxval,
  64.                                   node_array<num_type>& dist,
  65.                                   node_array<edge>& pred,
  66.                             const node_array<int>& side)
  67.   node_pq<num_type> PQ(G);
  68.   num_type a_min = maxval,    // minimal distance to an endpoint of 
  69.          b_min = maxval,    // an augmenting path in A resp. B
  70.            dv, dw, c, uv;
  71.   list<node> alist, blist;    // the lists of minimal endpoints
  72.   node v, w;
  73.   edge e;
  74.  
  75.   forall(v,free) {         // initialize distances and PQ
  76.     dist[v] = 0;
  77.     PQ.insert(v,0);
  78.     if( u[v]<=a_min ) {        // compute initial nodelist for A
  79.       if( u[v]<a_min ) {
  80.         alist.clear(); 
  81.         a_min = u[v]; 
  82.       }
  83.       alist.append(v);
  84.     }
  85.   }
  86.  
  87.   while( !PQ.empty() ) { 
  88.     v = PQ.del_min();        // dist[v] is the final distance of v
  89.  
  90.     dv = dist[v];
  91.     uv = u[v];
  92.  
  93.     /* if v is in A, update the nodelist for A
  94.      */
  95.     if( !side[v] && uv+dv<=a_min ) {    
  96.       if( uv+dv<a_min ) {
  97.         alist.clear(); 
  98.         a_min = uv+dv;
  99.       }
  100.       alist.append(v);
  101.     }
  102.  
  103.     /* stop if the actual distance becomes greater than the 
  104.        distance to an endpoint of an augmenting path already seen
  105.      */
  106.     if( a_min<dv || b_min<dv ) 
  107.       break;
  108.           
  109.     /* if v is in B, update the nodelist for B
  110.      */
  111.     if( side[v] && !G.outdeg(v) ) {
  112.       b_min = dv;
  113.       blist.append(v);
  114.     }
  115.  
  116.     /* perform one step of Dijkstra's algorithm
  117.      */
  118.     forall_adj_edges( e, v ) {         
  119.       w = G.target(e);    
  120.       dw = dist[w];
  121.       c = dv + uv + u[w] - weight[e];
  122.  
  123.       if (c < dv) c = dv;  /* rounding errors: u[v]+u[w]-weight[e]
  124.                                                might become negative */
  125.       if( c < dw ) { 
  126.         if( dw == maxval )
  127.            PQ.insert(w,c);
  128.         else
  129.            PQ.decrease_inf(w,c);
  130.         dist[w] = c;
  131.         pred[w] = e;
  132.       }
  133.     }
  134.   }
  135.  
  136.   /* return the appropriate list of nodes
  137.    */
  138.   if( a_min==b_min )
  139.     alist.conc( blist );
  140.   
  141.   return a_min<=b_min ? alist : blist;
  142. }
  143.  
  144.  
  145.  
  146. /* augment matching in one pass along paths of length 1 and 3 
  147. */
  148. static int mwbm_heuristic( graph& G, 
  149.                    const list<node>& A,
  150.                    const edge_array<num_type>& weight, 
  151.                    node_array<num_type>& u)
  152.   node v, w;
  153.   edge e, e2, eb;
  154.   int n = 0;
  155.   num_type max, max2, we;
  156.   node_array<edge> sec_edge(G,0);
  157.  
  158.   forall( v, A ) {            // for all nodes in A ...
  159.     max2 = 0; max = 0; eb = 0;
  160.     forall_adj_edges( e, v ) {        // compute edges with largest
  161.       we = weight[e]-u[target(e)];    // and second largest slack
  162.       if( we >= max2 ) {
  163.         if( we >= max ) {
  164.       max2 = max;  e2 = eb;
  165.           max = we;  eb = e;
  166.         }
  167.     else {
  168.       max2 = we;  e2 = e;
  169.     }
  170.       }
  171.     }
  172.  
  173.     if( eb ) {
  174.       w = target(eb);
  175.       if( !G.outdeg(w) ) {        // match eb and change u[] such
  176.         sec_edge[v] = e2;        // that e2 also gets slack 0
  177.         u[v] = max2;
  178.         u[w] = max-max2;
  179.         G.rev_edge(eb);
  180.         n++;
  181.       }
  182.       else {                // try to augment matching along
  183.         u[v] = max;            // path of length 3 given by sec_edge[]
  184.     e2 = G.first_adj_edge(w);
  185.     e = sec_edge[target(e2)];
  186.     if( e && !G.outdeg(target(e)) ) {
  187.       G.rev_edge(e); G.rev_edge(e2); G.rev_edge(eb);
  188.       n++;
  189.     }
  190.       }
  191.     }
  192.   }
  193.  
  194.   return n;
  195. }
  196.  
  197.  
  198.  
  199. /* compute a maximum weight matching in G
  200.  */
  201. static list<edge> compute_MWBM( graph& G, 
  202.                 const list<node>& A,
  203.                 const list<node>& B,
  204.                 const edge_array<num_type>& weight )
  205. {
  206.   num_type MAX, MIN;
  207.   Max_Value(MAX); Min_Value(MIN);
  208.   
  209.   num_type d_min;
  210.   node v, v_min;
  211.   edge e;
  212.   node_array<edge>     pred(G,nil);
  213.   node_array<num_type> dist(G,MAX), u(G,0);
  214.   node_array<int>      side(G,1), used(G,0);
  215.   int mark=0;            // nodes v with used[v]<mark are unused
  216.   node_list free;
  217.   list<node> vlist;
  218.   mwbm_heuristic(G,A,weight,u);
  219.  
  220.   forall(v,A) {
  221.      if( G.indeg(v)==0 && G.outdeg(v) ) {
  222.        free.append(v);
  223.        dist[v] = 0;
  224.       }
  225.       side[v]=0;
  226.   }
  227.   
  228.   while( !free.empty() ) {
  229.     mark++;            // mark all nodes as unused
  230.  
  231.     /* compute the list of possible endpoints
  232.      */
  233.     vlist = dijkstra(G,free,u,weight,MAX,dist,pred,side);
  234.  
  235.     forall( v_min, vlist ) {
  236.       v=v_min; 
  237.  
  238.       /* if v_min is not the first node of the list, check if the
  239.          augmenting path to v_min contains an used node
  240.        */
  241.       if( v_min!=vlist.head() ) {
  242.         e=pred[v];
  243.         while( e && used[v]<mark ) { 
  244.           v = source(e);
  245.           e = pred[v];
  246.         }
  247.       }
  248.  
  249.       /* if all nodes are unused, augment the matching along the path
  250.        */
  251.       if( used[v]<mark ) {
  252.         v = v_min; e = pred[v];
  253.         while( e ) { 
  254.           used[v]=mark;
  255.           v = source(e);
  256.           G.rev_edge(e);
  257.           e = pred[v];
  258.         }
  259.         free.del(v);
  260.         used[v]=mark;
  261.       }
  262.     }
  263.  
  264.     /* change the dual function
  265.      */
  266.     v_min = vlist.head();
  267.     d_min = side[v_min] ? dist[v_min] : u[v_min]+dist[v_min];
  268.     
  269.     forall(v,A) { 
  270.       if (d_min > dist[v]) 
  271.         u[v] -= d_min-dist[v];
  272.       dist[v] = MAX;
  273.     }
  274.   
  275.     forall(v,B) { 
  276.       if (d_min > dist[v]) 
  277.         u[v] += d_min-dist[v];
  278.       dist[v] = MAX;
  279.     }
  280.   }
  281.  
  282.   /* compute the result
  283.    */
  284.   list<edge> result;
  285.   forall(v,B) 
  286.     forall_adj_edges(e,v) result.append(e);
  287.   forall(e,result) G.rev_edge(e);
  288.   
  289.   return result;
  290. }
  291.